﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace DllInjector
{
    class Win32
    {
        [DllImport("kernel32")]
        public static extern IntPtr LoadLibrary(
            string lpFileName
            );

        [DllImport("kernel32.dll")]
        public static extern bool FreeLibrary(IntPtr hModule);

        [DllImport("kernel32")]
        public static extern IntPtr GetProcAddress(
            IntPtr hModule,
            string lpProcName
            );

        [DllImport("kernel32")]
        public static extern IntPtr OpenProcess(
            uint dwDesiredAccess,
            bool bInheritHandle,
            int dwProcessId
            );

        [DllImport("kernel32")]
        public static extern bool CloseHandle(
            IntPtr hObject
            );

        [DllImport("kernel32")]
        public static extern IntPtr VirtualAllocEx(
            IntPtr hProcess,
            uint lpAddress,
            uint dwSize,
            uint flAllocationType,
            uint flProtect
            );

        [DllImport("kernel32")]
        public static extern IntPtr VirtualFreeEx(
            IntPtr hProcess,
            uint lpAddress, 
            uint dwSize, 
            uint dwFreeType);

        [DllImport("kernel32")]
        public static extern bool WriteProcessMemory(
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            byte[] lpBuffer,
            uint nSize,
            out IntPtr lpNumberOfBytesWritten
            );

        [DllImport("kernel32")]
        public static extern IntPtr CreateRemoteThread(
            IntPtr hProcess,
            uint lpThreadAttributes,
            uint dwStackSize,
            IntPtr lpStartAddress,
            IntPtr lpParameter,
            uint dwCreationFlags,
            uint lpThreadId
            );

        [DllImport("kernel32.dll")]
        public static extern bool CreateProcess(
            string lpApplicationName,
            string lpCommandLine, 
            ref SecurityAttributes lpProcessAttributes,
            ref SecurityAttributes lpThreadAttributes, 
            bool bInheritHandles,
            uint dwCreationFlags, 
            IntPtr lpEnvironment, 
            string lpCurrentDirectory,
            [In] ref StartupInfo lpStartupInfo,
            out ProcessInfo lpProcessInformation);


        [DllImport("kernel32")]
        public static extern uint ResumeThread(
            IntPtr hThread
            );

        [DllImport("kernel32")]
        public static extern uint WaitForSingleObject(
            IntPtr hHandle,
            uint dwMiliseconds
            );

        public static class AccessRights
        {
            /// <summary>
            /// Standard rights required to mess with an object's security descriptor, change, or delete the object.
            /// </summary>
            public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
            /// <summary>
            /// The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. Some object types do not support this access right.
            /// </summary>
            public const uint SYNCHRONIZE = 0x00100000;

            /// <summary>
            /// Required to terminate a process using TerminateProcess.
            /// </summary>
            public const uint PROCESS_TERMINATE = 0x0001;
            /// <summary>
            /// Required to create a thread.
            /// </summary>
            public const uint PROCESS_CREATE_THREAD = 0x0002;
            //public const uint PROCESS_SET_SESSIONID = 0x0004;
            /// <summary>
            /// Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
            /// </summary>
            public const uint PROCESS_VM_OPERATION = 0x0008;
            /// <summary>
            /// Required to read memory in a process using ReadProcessMemory.
            /// </summary>
            public const uint PROCESS_VM_READ = 0x0010;
            /// <summary>
            /// Required to write memory in a process using WriteProcessMemory.
            /// </summary>
            public const uint PROCESS_VM_WRITE = 0x0020;
            /// <summary>
            /// Required to duplicate a handle using DuplicateHandle.
            /// </summary>
            public const uint PROCESS_DUP_HANDLE = 0x0040;
            /// <summary>
            /// Required to create a process.
            /// </summary>
            public const uint PROCESS_CREATE_PROCESS = 0x0080;
            /// <summary>
            /// Required to set memory limits using SetProcessWorkingSetSize.
            /// </summary>
            public const uint PROCESS_SET_QUOTA = 0x0100;
            /// <summary>
            /// Required to set certain information about a process, such as its priority class (see SetPriorityClass).
            /// </summary>
            public const uint PROCESS_SET_INFORMATION = 0x0200;
            /// <summary>
            /// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob).
            /// </summary>
            public const uint PROCESS_QUERY_INFORMATION = 0x0400;
            /// <summary>
            /// Required to suspend or resume a process.
            /// </summary>
            public const uint PROCESS_SUSPEND_RESUME = 0x0800;
            /// <summary>
            /// Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION.
            /// </summary>
            public const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;

            /// <summary>
            /// All possible access rights for a process object.
            /// </summary>
            public const uint PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF;//0x001F0FFF on WinXP, should be changed to 0xFFFF on Vista/2k8

            /// <summary>
            /// Required to terminate a thread using TerminateThread.
            /// </summary>
            public const uint THREAD_TERMINATE = 0x0001;
            /// <summary>
            /// Required to suspend or resume a thread.
            /// </summary>
            public const uint THREAD_SUSPEND_RESUME = 0x0002;
            /// <summary>
            /// Required to read the context of a thread using <see cref="Imports.GetThreadContext"/>
            /// </summary>
            public const uint THREAD_GET_CONTEXT = 0x0008;
            /// <summary>
            /// Required to set the context of a thread using <see cref="Imports.SetThreadContext"/>
            /// </summary>
            public const uint THREAD_SET_CONTEXT = 0x0010;
            /// <summary>
            /// Required to read certain information from the thread object, such as the exit code (see GetExitCodeThread).
            /// </summary>
            public const uint THREAD_QUERY_INFORMATION = 0x0040;
            /// <summary>
            /// Required to set certain information in the thread object.
            /// </summary>
            public const uint THREAD_SET_INFORMATION = 0x0020;
            /// <summary>
            /// Required to set the impersonation token for a thread using SetThreadToken.
            /// </summary>
            public const uint THREAD_SET_THREAD_TOKEN = 0x0080;
            /// <summary>
            /// Required to use a thread's security information directly without calling it by using a communication mechanism that provides impersonation services.
            /// </summary>
            public const uint THREAD_IMPERSONATE = 0x0100;
            /// <summary>
            /// Required for a server thread that impersonates a client.
            /// </summary>
            public const uint THREAD_DIRECT_IMPERSONATION = 0x0200;

            /// <summary>
            /// All possible access rights for a thread object.
            /// </summary>
            public const uint THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3FF;
        }

        public static class MemoryAllocType
        {
            /// <summary>
            /// Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages. The function initializes the memory to zero. 
            ///
            ///To reserve and commit pages in one step, call VirtualAllocEx with MEM_COMMIT | MEM_RESERVE.
            ///
            ///The function fails if you attempt to commit a page that has not been reserved. The resulting error code is ERROR_INVALID_ADDRESS.
            ///
            ///An attempt to commit a page that is already committed does not cause the function to fail. This means that you can commit pages without first determining the current commitment state of each page.
            /// </summary>
            public const uint MEM_COMMIT = 0x00001000;

            /// <summary>
            /// Reserves a range of the process's virtual address space without allocating any actual physical storage in memory or in the paging file on disk.
            ///
            ///You commit reserved pages by calling VirtualAllocEx again with MEM_COMMIT.
            /// </summary>
            public const uint MEM_RESERVE = 0x00002000;

            /// <summary>
            /// Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages should not be read from or written to the paging file. However, the memory block will be used again later, so it should not be decommitted. This value cannot be used with any other value.
            ///
            ///Using this value does not guarantee that the range operated on with MEM_RESET will contain zeroes. If you want the range to contain zeroes, decommit the memory and then recommit it.
            /// </summary>
            public const uint MEM_RESET = 0x00080000;

            /// <summary>
            /// Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages.
            ///
            ///This value must be used with MEM_RESERVE and no other values.
            /// </summary>
            public const uint MEM_PHYSICAL = 0x00400000;

            /// <summary>
            /// Allocates memory at the highest possible address. 
            /// </summary>
            public const uint MEM_TOP_DOWN = 0x00100000;
        }

        public static class MemoryProtectType
        {
            /// <summary>
            /// Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation. 
            /// </summary>
            public const uint PAGE_EXECUTE = 0x10;
            /// <summary>
            /// Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation. 
            /// </summary>
            public const uint PAGE_EXECUTE_READ = 0x20;
            /// <summary>
            /// Enables execute, read, and write access to the committed region of pages. 
            /// </summary>
            public const uint PAGE_EXECUTE_READWRITE = 0x40;
            /// <summary>
            /// Enables execute, read, and write access to the committed region of image file code pages. The pages are shared read-on-write and copy-on-write. 
            /// </summary>
            public const uint PAGE_EXECUTE_WRITECOPY = 0x80;

            /// <summary>
            /// Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation exception, called a general protection (GP) fault. 
            /// </summary>
            public const uint PAGE_NOACCESS = 0x01;
            /// <summary>
            /// Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
            /// </summary>
            public const uint PAGE_READONLY = 0x02;
            /// <summary>
            /// Enables both read and write access to the committed region of pages.
            /// </summary>
            public const uint PAGE_READWRITE = 0x04;
            /// <summary>
            /// Gives copy-on-write protection to the committed region of pages. 
            /// </summary>
            public const uint PAGE_WRITECOPY = 0x08;

            /// <summary>
            ///Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm. For more information, see Creating Guard Pages.
            ///
            ///When an access attempt leads the system to turn off guard page status, the underlying page protection takes over.
            ///
            ///If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
            ///
            ///This value cannot be used with PAGE_NOACCESS.
            /// </summary>
            public const uint PAGE_GUARD = 0x100;
            /// <summary>
            /// Does not allow caching of the committed regions of pages in the CPU cache. The hardware attributes for the physical memory should be specified as "no cache." This is not recommended for general usage. It is useful for device drivers, for example, mapping a video frame buffer with no caching.
            ///
            ///This value cannot be used with PAGE_NOACCESS.
            /// </summary>
            public const uint PAGE_NOCACHE = 0x200;
            /// <summary>
            /// Enables write-combined memory accesses. When enabled, the processor caches memory write requests to optimize performance. Thus, if two requests are made to write to the same memory address, only the more recent write may occur.
            ///
            ///Note that the PAGE_GUARD and PAGE_NOCACHE flags cannot be specified with PAGE_WRITECOMBINE. If an attempt is made to do so, the SYSTEM_INVALID_PAGE_PROTECTION NT error code is returned by the function.
            /// </summary>
            public const uint PAGE_WRITECOMBINE = 0x400;
        }

        public static class MemoryFreeType
        {
            /// <summary>
            /// Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.
            ///
            ///The function does not fail if you attempt to decommit an uncommitted page. This means that you can decommit a range of pages without first determining their current commitment state.
            ///
            ///Do not use this value with MEM_RELEASE.
            /// </summary>
            public const uint MEM_DECOMMIT = 0x4000;

            /// <summary>
            /// Releases the specified region of pages. After the operation, the pages are in the free state.
            ///
            /// If you specify this value, dwSize must be 0 (zero), and lpAddress must point to the base address returned by the VirtualAllocEx function when the region is reserved. The function fails if either of these conditions is not met.
            ///
            /// If any pages in the region are committed currently, the function first decommits, and then releases them.
            ///
            /// The function does not fail if you attempt to release pages that are in different states, some reserved and some committed. This means that you can release a range of pages without first determining the current commitment state.
            ///
            /// Do not use this value with MEM_DECOMMIT.
            /// </summary>
            public const uint MEM_RELEASE = 0x8000;
        }

        [Flags]
        public enum ProcessCreationFlags
        {
            NORMAL_PRIORITY_CLASS = 0x00000020,
            CREATE_SUSPENDED = 0x00000004,
            NORMAL_SUSPENDED = NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct ProcessInfo
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 ProcessId;
            public Int32 ThreadId;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct SecurityAttributes
        {
            public int length;
            public IntPtr lpSecurityDescriptor;
            public bool bInheritHandle;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct StartupInfo
        {
            public uint cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
    }
}
